by Tem Cavanagh as part of STAT6020 Predictive Analytics (Master of Data Science)
Abstract: This paper examines the classification accuracy of machine learning methods in detecting wilt disease present in Japanese pine and oak trees. A comparative assessment is conducted on the wilt dataset (UCI Machine Learning Repository) whereby the classification accuracy of Decision Trees (Random Forests) and Support Vector Machines are analysed. Formal quantitative assessment of results are carried out in combination with qualitative assessment through visualisation of results. FINDINGS. CONCLUSIONS.
Introduction:
Forests are becoming increasingly susceptible to damage and degradation by way of plant diseases caused by insects and climate change (Food and Agriculture Organization of the United Nations Regional Office for Asia and the Pacific 2010; Garrett et. al. 2006).
Discolouration of foliage is often an indicator of a diseased tree (Johnson). Johnson et. al. have conducted high resolution satellite image surveys with the purpose of identifying diseased pine and oak trees in Japan. The resulting images are shown below:
The objective of this project is to assess and compare the classification accuracy of statistical learning methods in detecting and classifying diseased trees. The overarching aim of this project is to demonstrate the applicability of statistical learning techniques as preventative measures against forest degredation.
Data:
The data for this project was sourced from the UCI Machine Learning Repository (http://archive.ics.uci.edu/ml/datasets/wilt).
The data was originally collected by the Centre for Environmental Remote Sensing through satellite imagery which was in turn ‘pansharpened’ to obtain spatially and spectrally accurate image measurements.
The total dimensions of the dataset is 4838 observations across 6 variables.
Variable descriptions:
| class |
Factor |
‘w’ (wilt diseased trees), ‘n’ (all other land cover) |
| GLCM_Pan |
Num |
Grey level mean texture (Pan band) |
| Mean_Green |
Num |
Mean green value |
| Mean_Red |
Num |
Mean red value |
| Mean_NIR |
Num |
Mean near infra-red value |
| SD_Pan |
Num |
Standard deviation (Pan band) |
Known preceding interventions and pre-processing:
In its original form, the data is made up of two separate .csv files which consist of one training set of 4338 observations and one test set of 500 observations.
Undertaken interventions and pre-processing:
- Remove observation 480 from imported test dataset: This observation appeared to be a significant outlier.
- Merge test and train datasets into single dataset.
- Split the merged dataset into a training set comprising 80% of observations and a test set comprising 20% of observations.
Note: Scaling of observations was not used.
Accordingly, the training dataset consists of 3,870 observations. 3,658 of which are classified as disease free (‘n’) and 212 are classified as diseased (‘w’).
The test dataset consists of 968 observations. 919 of which are classified as disease free (‘n’) and 49 are classified as diseased (‘w’).
Methods:
R version
[1] "R version 4.0.2 (2020-06-22)"
Decision Trees
class.rp = rpart(class ~ ., data = wilt_train)
Perform cross-validation and pruning of decision tree
prune.train.matrix$byClass['Specificity']
Random Forests
There is no requirement for cross-validation when using random forests (Breiman, 2001).
Support Vector Machines
svm_class = svm(class~., data=wilt_train)
windows.options(width=10, height=10)
Error in windows.options(width = 10, height = 10) :
could not find function "windows.options"
Linear kernel Support Vector Machine
bestmod
Call:
best.tune(method = svm, train.x = class ~ ., data = wilt_train, ranges = list(cost = c(0.001,
0.01, 0.1, 1, 10, 100)), kernel = "linear")
Parameters:
SVM-Type: C-classification
SVM-Kernel: linear
cost: 10
Number of Support Vectors: 330
Radial kernel Support Vector Machine
set.seed(0)
radtune.out=tune(svm, class~., data=wilt_train, kernel='radial',
ranges=list(cost=c(0.001,0.01,0.1,1,10,100),
gamma=c(0.01,0.1,1,2,3,4)))
bestmodrad = radtune.out$best.model
Results and Discussion:
The table below shows the classification results from the previously highlighted methods. Accuracy refers to the classification accuracy of a method when classifying observations across both of the predictive classes. Specificity refers to the classification accuracy of a method when classifying observations of the class ‘wilt’ only.
From the results obtained through the assessed methods, the radial support vector machine method has recorded the equal highest accuracy (99.07%) and the highest specificity (95.92%) on the test dataset. The random forest method recorded the second highest accuracy (99.07%) and specificity (91.84%) on the test dataset. Decision tree methods also performed comparatively well with accuracy and specificity results of 98.35% and 85.71% respectively for the un-pruned decision tree, and 98.14% and 81.63% respectively for the pruned decision tree. This is an observable reduction in specificity in the pruned decision tree in trade for a relatively minor simplification in the resulting decision tree model (16 terminal nodes versus 13 terminal nodes when pruned). It is clear from analysis of the results that all methods recorded similar accuracy results when each model was applied on the test dataset. As such, it can be stated that no model in particular could be described to have been over-fitted to the training dataset. It is also clear from analysis that all methods tended to perform with less precision when specificity was considered. Assessing the precision in specificity of a method is important when consideration is given to the potential negative consequences of a false-negative wilt disease classification. On this basis, specificity as a determining factor in the overall assessment of the classification accuracy simply cannot be ignored.
Conclusions:
In conclusion, this project has assessed and compared decision trees, random forest ensembles for decision trees and support vector machines in the context of identifying diseased trees in the wilt dataset. A radial kernel support vector machine was identified as a highly accurate and specific classifying method for the detection of wilt diseased trees.
References:
Breiman, L. (2001). “Random Forests”, https://www.stat.berkeley.edu/~breiman/randomforest2001.pdf
Food and Agriculture Organization of the United Nations Regional Office for Asia and the Pacific. (2010). “Japan Forestry Outlook Study.” In Asia-Pacific Forestry Sector Outlook Study II Working Paper Series, 9–10. Working Paper No. APFSOS II/WP/2010/30.
Johnson, B., Tateishi, R., Hoan, N. (2013). “A hybrid pansharpening approach and multiscale object-based image analysis for mapping diseased pine and oak trees”, International Journal of Remote Sensing, 34 (20), 6969-6982.
Garrett, K., Dendy, S., Frank, E., Rouse, M., Travers, M., (2006) “Climate change effects on plant disease: genomes to ecosystems,” Annual Review of Phytopathology, Vol. 44, pp. 489–509, 2006.
LS0tCnRpdGxlOiBBIENvbXBhcmF0aXZlIEFzc2Vzc21lbnQgb2YgTWFjaGluZSBMZWFybmluZyBDbGFzc2lmaWNhdGlvbiBNZXRob2RzIEZvciBUaGUKICBEZXRlY3Rpb24gb2YgV2lsdCBEaXNlYXNlIGluIFBpbmUgYW5kIE9hayBUcmVlcwpvdXRwdXQ6CiAgd29yZF9kb2N1bWVudDogZGVmYXVsdAogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQKICBodG1sX2RvY3VtZW50OgogICAgZGZfcHJpbnQ6IHBhZ2VkCiAgcGRmX2RvY3VtZW50OiBkZWZhdWx0Ci0tLQoKCmJ5IFRlbSBDYXZhbmFnaCBhcyBwYXJ0IG9mIFNUQVQ2MDIwIFByZWRpY3RpdmUgQW5hbHl0aWNzIChNYXN0ZXIgb2YgRGF0YSBTY2llbmNlKQoKKioqCgo8Y2VudGVyPgoKKipBYnN0cmFjdDoqKiAqVGhpcyBwYXBlciBleGFtaW5lcyB0aGUgY2xhc3NpZmljYXRpb24gYWNjdXJhY3kgb2YgbWFjaGluZSBsZWFybmluZyBtZXRob2RzIGluKgoqZGV0ZWN0aW5nIHdpbHQgZGlzZWFzZSBwcmVzZW50IGluIEphcGFuZXNlIHBpbmUgYW5kIG9hayB0cmVlcy4gQSBjb21wYXJhdGl2ZSoKKmFzc2Vzc21lbnQgaXMgY29uZHVjdGVkIG9uIHRoZSB3aWx0IGRhdGFzZXQgKFVDSSBNYWNoaW5lIExlYXJuaW5nIFJlcG9zaXRvcnkpKgoqd2hlcmVieSB0aGUgY2xhc3NpZmljYXRpb24gYWNjdXJhY3kgb2YgRGVjaXNpb24gVHJlZXMgKFJhbmRvbSBGb3Jlc3RzKSBhbmQgKgoqU3VwcG9ydCBWZWN0b3IgTWFjaGluZXMgYXJlIGFuYWx5c2VkLiBGb3JtYWwgcXVhbnRpdGF0aXZlIGFzc2Vzc21lbnQgb2YgcmVzdWx0cyoKKmFyZSBjYXJyaWVkIG91dCBpbiBjb21iaW5hdGlvbiB3aXRoIHF1YWxpdGF0aXZlIGFzc2Vzc21lbnQgdGhyb3VnaCB2aXN1YWxpc2F0aW9uKiAKKm9mIHJlc3VsdHMuIEZJTkRJTkdTLiBDT05DTFVTSU9OUy4qCgo8L2NlbnRlcj4KCioqKgojIyMgSW50cm9kdWN0aW9uOgoKRm9yZXN0cyBhcmUgYmVjb21pbmcgaW5jcmVhc2luZ2x5IHN1c2NlcHRpYmxlIHRvIGRhbWFnZSBhbmQgZGVncmFkYXRpb24gYnkgCndheSBvZiBwbGFudCBkaXNlYXNlcyBjYXVzZWQgYnkgaW5zZWN0cyBhbmQgY2xpbWF0ZSBjaGFuZ2UgKEZvb2QgYW5kIEFncmljdWx0dXJlIApPcmdhbml6YXRpb24gb2YgdGhlIFVuaXRlZCBOYXRpb25zIFJlZ2lvbmFsIE9mZmljZSBmb3IgQXNpYSBhbmQgdGhlIFBhY2lmaWMgMjAxMDsKR2FycmV0dCBldC4gYWwuIDIwMDYpLiAKCkRpc2NvbG91cmF0aW9uIG9mIGZvbGlhZ2UgaXMgb2Z0ZW4gYW4gaW5kaWNhdG9yIG9mIGEgZGlzZWFzZWQgdHJlZSAoSm9obnNvbikuIApKb2huc29uIGV0LiBhbC4gaGF2ZSBjb25kdWN0ZWQgaGlnaCByZXNvbHV0aW9uIHNhdGVsbGl0ZSBpbWFnZSBzdXJ2ZXlzIHdpdGggdGhlCnB1cnBvc2Ugb2YgaWRlbnRpZnlpbmcgZGlzZWFzZWQgcGluZSBhbmQgb2FrIHRyZWVzIGluIEphcGFuLiBUaGUgcmVzdWx0aW5nIGltYWdlcwphcmUgc2hvd24gYmVsb3c6CgohW0ZpZ3VyZSAxOiBEaXNlYXNlZCBjbGFzc2lmaWVkIHRyZWVzIChTb3VyY2U6IEpvaG5zb24pXSgvVXNlcnMvdGVtdWVyYWNhdmFuYWdoL0RvY3VtZW50cy9Eb2N1bWVudHMvRGF0YSBTY2llbmNlL1NUQVQ2MDIwIC0gUHJlZGljdGl2ZSBBbmFseXRpY3MvUHJvamVjdC93aWx0X2ltYWdlLnBuZyl7d2lkdGg9NTAlfQoKVGhlIG9iamVjdGl2ZSBvZiB0aGlzIHByb2plY3QgaXMgdG8gYXNzZXNzIGFuZCBjb21wYXJlIHRoZSBjbGFzc2lmaWNhdGlvbiBhY2N1cmFjeSBvZiAKc3RhdGlzdGljYWwgbGVhcm5pbmcgbWV0aG9kcyBpbiBkZXRlY3RpbmcgYW5kIGNsYXNzaWZ5aW5nIGRpc2Vhc2VkIHRyZWVzLiBUaGUgb3ZlcmFyY2hpbmcKYWltIG9mIHRoaXMgcHJvamVjdCBpcyB0byBkZW1vbnN0cmF0ZSB0aGUgYXBwbGljYWJpbGl0eSBvZiBzdGF0aXN0aWNhbCBsZWFybmluZyB0ZWNobmlxdWVzIGFzIApwcmV2ZW50YXRpdmUgbWVhc3VyZXMgYWdhaW5zdCBmb3Jlc3QgZGVncmVkYXRpb24uCgoqKioKIyMjIERhdGE6CgpUaGUgZGF0YSBmb3IgdGhpcyBwcm9qZWN0IHdhcyBzb3VyY2VkIGZyb20gdGhlIFVDSSBNYWNoaW5lIExlYXJuaW5nIFJlcG9zaXRvcnkgKGh0dHA6Ly9hcmNoaXZlLmljcy51Y2kuZWR1L21sL2RhdGFzZXRzL3dpbHQpLgoKVGhlIGRhdGEgd2FzIG9yaWdpbmFsbHkgY29sbGVjdGVkIGJ5IHRoZSBDZW50cmUgZm9yIEVudmlyb25tZW50YWwgUmVtb3RlIFNlbnNpbmcKdGhyb3VnaCBzYXRlbGxpdGUgaW1hZ2VyeSB3aGljaCB3YXMgaW4gdHVybiAncGFuc2hhcnBlbmVkJyB0byBvYnRhaW4gc3BhdGlhbGx5IAphbmQgc3BlY3RyYWxseSBhY2N1cmF0ZSBpbWFnZSBtZWFzdXJlbWVudHMuCgpUaGUgdG90YWwgZGltZW5zaW9ucyBvZiB0aGUgZGF0YXNldCBpcyA0ODM4IG9ic2VydmF0aW9ucyBhY3Jvc3MgNiB2YXJpYWJsZXMuCgojIyMjIFZhcmlhYmxlIGRlc2NyaXB0aW9uczogIAoKVmFyaWFibGUgICAgICAgfCBUeXBlICAgfCBEZXNjcmlwdGlvbgotLS0tLS0tLS0tLS0tLS18LS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoqKmNsYXNzKiogICAgICB8IEZhY3RvciB8ICd3JyAod2lsdCBkaXNlYXNlZCB0cmVlcyksICduJyAoYWxsIG90aGVyIGxhbmQgY292ZXIpICAKKipHTENNX1BhbioqICAgfCBOdW0gICAgfCBHcmV5IGxldmVsIG1lYW4gdGV4dHVyZSAoUGFuIGJhbmQpICAKKipNZWFuX0dyZWVuKiogfCBOdW0gICAgfCBNZWFuIGdyZWVuIHZhbHVlICAKKipNZWFuX1JlZCoqICAgfCBOdW0gICAgfCBNZWFuIHJlZCB2YWx1ZSAgCioqTWVhbl9OSVIqKiAgIHwgTnVtICAgIHwgTWVhbiBuZWFyIGluZnJhLXJlZCB2YWx1ZSAgCioqU0RfUGFuKiogICAgIHwgTnVtICAgIHwgU3RhbmRhcmQgZGV2aWF0aW9uIChQYW4gYmFuZCkgIAoKKipLbm93biBwcmVjZWRpbmcgaW50ZXJ2ZW50aW9ucyBhbmQgcHJlLXByb2Nlc3Npbmc6KiogIAoKSW4gaXRzIG9yaWdpbmFsIGZvcm0sIHRoZSBkYXRhIGlzIG1hZGUgdXAgb2YgdHdvIHNlcGFyYXRlIC5jc3YgZmlsZXMgd2hpY2ggY29uc2lzdCBvZiBvbmUgdHJhaW5pbmcgc2V0IG9mIDQzMzggb2JzZXJ2YXRpb25zIGFuZCBvbmUgdGVzdCBzZXQgb2YgNTAwIG9ic2VydmF0aW9ucy4KCioqVW5kZXJ0YWtlbiBpbnRlcnZlbnRpb25zIGFuZCBwcmUtcHJvY2Vzc2luZzoqKiAgCgoqIFJlbW92ZSBvYnNlcnZhdGlvbiA0ODAgZnJvbSBpbXBvcnRlZCB0ZXN0IGRhdGFzZXQ6IFRoaXMgb2JzZXJ2YXRpb24gYXBwZWFyZWQgdG8gYmUgYSBzaWduaWZpY2FudCBvdXRsaWVyLiAgIAoqIE1lcmdlIHRlc3QgYW5kIHRyYWluIGRhdGFzZXRzIGludG8gc2luZ2xlIGRhdGFzZXQuICAKKiBTcGxpdCB0aGUgbWVyZ2VkIGRhdGFzZXQgaW50byBhIHRyYWluaW5nIHNldCBjb21wcmlzaW5nIDgwJSBvZiBvYnNlcnZhdGlvbnMgYW5kIGEgdGVzdCAKc2V0IGNvbXByaXNpbmcgMjAlIG9mIG9ic2VydmF0aW9ucy4gIAoKKk5vdGU6IFNjYWxpbmcgb2Ygb2JzZXJ2YXRpb25zIHdhcyBub3QgdXNlZC4qICAKCkFjY29yZGluZ2x5LCB0aGUgdHJhaW5pbmcgZGF0YXNldCBjb25zaXN0cyBvZiAzLDg3MCBvYnNlcnZhdGlvbnMuIDMsNjU4IG9mIHdoaWNoIGFyZSBjbGFzc2lmaWVkCmFzIGRpc2Vhc2UgZnJlZSAoJ24nKSBhbmQgMjEyIGFyZSBjbGFzc2lmaWVkIGFzIGRpc2Vhc2VkICgndycpLiAgCgpUaGUgdGVzdCBkYXRhc2V0IGNvbnNpc3RzIG9mIDk2OCBvYnNlcnZhdGlvbnMuIDkxOSBvZiB3aGljaCBhcmUgY2xhc3NpZmllZCBhcyBkaXNlYXNlIGZyZWUgKCduJykgCmFuZCA0OSBhcmUgY2xhc3NpZmllZCBhcyBkaXNlYXNlZCAoJ3cnKS4KCmBgYHtyIGxpYnJhcmllcywgaW5jbHVkZT1GQUxTRX0KbGlicmFyeSh2aXNOZXR3b3JrKQpsaWJyYXJ5KHNwYXJrbGluZSkKbGlicmFyeShycGFydCkKbGlicmFyeShyYW5kb21Gb3Jlc3QpCmxpYnJhcnkoY2FyZXQpCmxpYnJhcnkoZTEwNzEpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHRpbnl0ZXgpCmBgYAoKCmBgYHtyIHNldC1kYXRhLCBpbmNsdWRlPUZBTFNFfQpzZXR3ZCgiL1VzZXJzL3RlbXVlcmFjYXZhbmFnaC9Eb2N1bWVudHMvRG9jdW1lbnRzL0RhdGEgU2NpZW5jZS9TVEFUNjAyMCAtIFByZWRpY3RpdmUgQW5hbHl0aWNzL1Byb2plY3QiKQoKd2lsdCA9IHJlYWQuY3N2KCJ3aWx0X3RyYWluaW5nLmNzdiIsIHN0cmluZ3NBc0ZhY3RvcnMgPSBUUlVFKQp3aWx0X3Rlc3QgPSByZWFkLmNzdigid2lsdF90ZXN0aW5nLmNzdiIsIHN0cmluZ3NBc0ZhY3RvcnMgPSBUUlVFKQoKIyBSZW1vdmUgcm93IDQ4MCBmcm9tIHRlc3QgCndpbHRfdGVzdCA9IHdpbHRfdGVzdFstYyg0ODApLF0KCiMgTWVyZ2UgZGF0YSBzZXRzCndpbHQgPSByYmluZCh3aWx0LCB3aWx0X3Rlc3QpCgojIENoZWNrIG1lcmdlZCBkYXRhCndpbHRbIWNvbXBsZXRlLmNhc2VzKHdpbHQpLF0gIyBObyBtaXNzaW5nIHZhbHVlcwpkaW0od2lsdCkgIyBDaGVjayBkaW1lbnNpb25zCm5sZXZlbHMod2lsdCRjbGFzcykgIyBDaGVjayBjbGFzcyBmYWN0b3IgbGV2ZWxzCnRhYmxlKHdpbHQkY2xhc3MpICMgQ2hlY2sgY2xhc3NpZmljYXRpb25zCgojIFNwbGl0IHRyYWluL3Rlc3Qgc2V0cwpzZXQuc2VlZCgwKSAjIFNldCBzZWVkIGZvciByZXByb2R1Y2liaWxpdHkgCgojIFNlbGVjdCA4MCUgb2YgZGF0YSBhcyBzYW1wbGUgZnJvbSB0b3RhbCAnbicgcm93cyBvZiB0aGUgZGF0YSAgCnNhbXBsZSA9IHNhbXBsZS5pbnQobiA9IG5yb3cod2lsdCksIHNpemUgPSBmbG9vciguOCpucm93KHdpbHQpKSwgcmVwbGFjZSA9IEYpCndpbHRfdHJhaW4gPSB3aWx0W3NhbXBsZSwgXQp3aWx0X3Rlc3QgPSB3aWx0Wy1zYW1wbGUsIF0KYGBgCgoKCioqKgojIyMgTWV0aG9kczoKClIgdmVyc2lvbgoKYGBge3IgdmVyc2lvbiwgZWNobz1GQUxTRX0KI1JTdHVkaW8uVmVyc2lvbigpJHZlcnNpb24KUi5WZXJzaW9uKCkkdmVyc2lvbi5zdHJpbmcKYGBgCgojIyMjIERlY2lzaW9uIFRyZWVzCgpgYGB7ciBkZWNpc2lvbi10cmVlfQpjbGFzcy5ycCA9IHJwYXJ0KGNsYXNzIH4gLiwgZGF0YSA9IHdpbHRfdHJhaW4pCmBgYAoKYGBge3IgZGVjaXNpb24tdHJlZXZpcywgZWNobz1GQUxTRSwgZmlnLmhlaWdodCA9IDMsIGZpZy53aWR0aCA9IDMsIGZpZy5hbGlnbiA9ICJjZW50ZXIifQp2aXNUcmVlKGNsYXNzLnJwLCBtYWluID0gIldpbHQgRGVjaXNpb24gVHJlZSIsd2lkdGggPSAiODAlIiwgIGhlaWdodCA9ICI0NTBweCIpCmBgYAoKYGBge3IgdHJlZS10cmFpbiwgaW5jbHVkZT1GQUxTRX0KcnAudHJhaW4gPSBwcmVkaWN0KGNsYXNzLnJwLCB3aWx0X3RyYWluLCB0eXBlID0gImNsYXNzIikKcnAudHJhaW4ubWF0cml4ID0gY29uZnVzaW9uTWF0cml4KHJwLnRyYWluLCB3aWx0X3RyYWluJGNsYXNzKQpycC50cmFpbi5tYXRyaXgkb3ZlcmFsbFsnQWNjdXJhY3knXQpycC50cmFpbi5tYXRyaXgkYnlDbGFzc1snU3BlY2lmaWNpdHknXQpgYGAKCmBgYHtyIHRyZWUtdGVzdCwgaW5jbHVkZT1GQUxTRX0KIyBQcmVkaWN0IG9uIHRlc3Qgc2V0CnJwLnByZWRpY3QgPSBwcmVkaWN0KGNsYXNzLnJwLCB3aWx0X3Rlc3QsIHR5cGUgPSAiY2xhc3MiKQpycC5tYXRyaXggPSBjb25mdXNpb25NYXRyaXgocnAucHJlZGljdCwgd2lsdF90ZXN0JGNsYXNzKQpycC5tYXRyaXgkb3ZlcmFsbFsnQWNjdXJhY3knXQpycC5tYXRyaXgkYnlDbGFzc1snU3BlY2lmaWNpdHknXQpgYGAKClBlcmZvcm0gY3Jvc3MtdmFsaWRhdGlvbiBhbmQgcHJ1bmluZyBvZiBkZWNpc2lvbiB0cmVlCmBgYHtyIHRyZWUtY3YsIHJlc3VsdHM9J2hpZGUnfQpzZXQuc2VlZCgwKQp0cmVlLmNsYXNzLmN2ID0gcHJpbnRjcChjbGFzcy5ycCkgIyBDcmVhdGUgbWF0cml4Cm1pbl9taXNjbGFzcyA9IHdoaWNoLm1pbih0cmVlLmNsYXNzLmN2WywgInhlcnJvciJdKSAjIEZpbmQgY29zdC1jb21wbGV4aXR5IHBhcmFtZXRlciB3aXRoIG1pbiBDViBlcnJvcgojIFJlc29sdmUgdGllcyB1c2luZyB0aGUgc2ltcGxlc3QgbW9kZWwgCndoaWxlKG1pbl9taXNjbGFzcyA8IGxlbmd0aCh0cmVlLmNsYXNzLmN2WyAsICJ4ZXJyb3IiXSkgJiYKICAgICAgdHJlZS5jbGFzcy5jdlttaW5fbWlzY2xhc3MsICJ4ZXJyb3IiXT09dHJlZS5jbGFzcy5jdlttaW5fbWlzY2xhc3MrMSwgInhlcnJvciJdKXsKICBtaW5fbWlzY2xhc3MgPSBtaW5fbWlzY2xhc3MgKyAxfQpDUCA9IHRyZWUuY2xhc3MuY3ZbbWluX21pc2NsYXNzLCAiQ1AiXSAjIENvc3QtY29tcGxleGl0eSBjb3JyZXNwb25kaW5nIHRvIG1pbiBDViBlcnJvcgp0cmVlLmNsYXNzLnBydW5lZCA9IHBydW5lKHRyZWUgPSBjbGFzcy5ycCwgY3AgPSBDUCkgIyBQcnVuZSBiZXN0IHRyZWUgY29ycmVzcG9uZGluZyB0byBtaW4gQ1YgZXJyb3IKYGBgCgpgYGB7ciB0cmVlLXZpcywgZWNobz1GQUxTRX0KdmlzVHJlZSh0cmVlLmNsYXNzLnBydW5lZCwgbWFpbiA9ICJQcnVuZWQgRGVjaXNpb24gVHJlZSIsIHdpZHRoID0gIjgwJSIsICBoZWlnaHQgPSAiNDUwcHgiKQpgYGAKCgpgYGB7ciBwcnVuZS10cmFpbiwgaW5jbHVkZT1GQUxTRX0KcnAucHJ1bmUudHJhaW4ucHJlZGljdCA9IHByZWRpY3QodHJlZS5jbGFzcy5wcnVuZWQsIHdpbHRfdHJhaW4sIHR5cGUgPSAiY2xhc3MiKQpwcnVuZS50cmFpbi5tYXRyaXggPSBjb25mdXNpb25NYXRyaXgocnAucHJ1bmUudHJhaW4ucHJlZGljdCwgd2lsdF90cmFpbiRjbGFzcykKcHJ1bmUudHJhaW4ubWF0cml4JG92ZXJhbGxbJ0FjY3VyYWN5J10KcHJ1bmUudHJhaW4ubWF0cml4JGJ5Q2xhc3NbJ1NwZWNpZmljaXR5J10KYGBgCgpgYGB7ciBwcnVuZS1wcmVkaWN0LCBpbmNsdWRlPUZBTFNFfQpycC5wcnVuZS5wcmVkaWN0ID0gcHJlZGljdCh0cmVlLmNsYXNzLnBydW5lZCwgd2lsdF90ZXN0LCB0eXBlID0gImNsYXNzIikKcHJ1bmUubWF0cml4ID0gY29uZnVzaW9uTWF0cml4KHJwLnBydW5lLnByZWRpY3QsIHdpbHRfdGVzdCRjbGFzcykKcHJ1bmUubWF0cml4JG92ZXJhbGxbJ0FjY3VyYWN5J10KcHJ1bmUubWF0cml4JGJ5Q2xhc3NbJ1NwZWNpZmljaXR5J10KYGBgCgojIyMjIFJhbmRvbSBGb3Jlc3RzCgpgYGB7ciByYW5kb20tZm9yZXN0LCByZXN1bHRzPSJoaWRlIn0Kc2V0LnNlZWQoMCkKZm9yZXN0LnRyYWluID0gcmFuZG9tRm9yZXN0KGNsYXNzIH4gLiwgZGF0YSA9IHdpbHRfdHJhaW4sIG10cnkgPSA1LCBpbXBvcnRhbmNlID0gVFJVRSwgbnRyZWUgPSAxMDAwKQpgYGAKCmBgYHtyLCBlY2hvPUZBTFNFfQpmb3Jlc3QudHJhaW4KYGBgCgpgYGB7ciBwbG90LWZvcmVzdCwgZWNobz1GQUxTRX0KcGxvdChmb3Jlc3QudHJhaW4sIG1haW4gPSAiUmFuZG9tIEZvcmVzdCBFcnJvciBSYXRlIikKdmFySW1wUGxvdChmb3Jlc3QudHJhaW4sIG1haW4gPSAiSW1wb3J0YW5jZSBvZiBWYXJpYWJsZXMgaW4gUmFuZG9tIEZvcmVzdCIpCmBgYAoKYGBge3IgdHJhaW4tZm9yZXN0LCBpbmNsdWRlPUZBTFNFfQpmb3Jlc3QucHJlZGljdCA9IHByZWRpY3QoZm9yZXN0LnRyYWluLCB3aWx0X3RyYWluLCB0eXBlID0gImNsYXNzIikKZm9yZXN0LnRyYWluLm1hdHJpeCA9IGNvbmZ1c2lvbk1hdHJpeChmb3Jlc3QucHJlZGljdCwgd2lsdF90cmFpbiRjbGFzcykKZm9yZXN0LnRyYWluLm1hdHJpeCRvdmVyYWxsWydBY2N1cmFjeSddCmZvcmVzdC50cmFpbi5tYXRyaXgkYnlDbGFzc1snU3BlY2lmaWNpdHknXQpgYGAKCmBgYHtyIHByZWRpY3QtZm9yZXN0LCBpbmNsdWRlPUZBTFNFfQpmb3Jlc3QudGVzdCA9IHByZWRpY3QoZm9yZXN0LnRyYWluLCB3aWx0X3Rlc3QsIHR5cGUgPSAiY2xhc3MiKQpmb3Jlc3QubWF0cml4ID0gY29uZnVzaW9uTWF0cml4KGZvcmVzdC50ZXN0LCB3aWx0X3Rlc3QkY2xhc3MpCmZvcmVzdC5tYXRyaXgkb3ZlcmFsbFsnQWNjdXJhY3knXQpmb3Jlc3QubWF0cml4JGJ5Q2xhc3NbJ1NwZWNpZmljaXR5J10KYGBgCgpUaGVyZSBpcyBubyByZXF1aXJlbWVudCBmb3IgY3Jvc3MtdmFsaWRhdGlvbiB3aGVuIHVzaW5nIHJhbmRvbSBmb3Jlc3RzIChCcmVpbWFuLCAyMDAxKS4KCiMjIyMgU3VwcG9ydCBWZWN0b3IgTWFjaGluZXMKCmBgYHtyIHN2bX0Kc3ZtX2NsYXNzID0gc3ZtKGNsYXNzfi4sIGRhdGE9d2lsdF90cmFpbikKYGBgCgpgYGB7ciwgZWNobz1GQUxTRX0Kc3ZtX2NsYXNzCmBgYAoKYGBge3J9CnBsb3Qoc3ZtX2NsYXNzLCBkYXRhID0gd2lsdF90cmFpbiwgTWVhbl9HcmVlbn5NZWFuX1JlZCwgCiAgICAgc2xpY2UgPSBsaXN0KEdMQ01fcGFuPTEsIE1lYW5fTklSPTEsIFNEX3Bhbj0xKSwgeGF4cz0iaSIpCmBgYAoKYGBge3Igc3ZtLXRyYWluLCBpbmNsdWRlPUZBTFNFfQpzdm1fdHJhaW5pbmdfcHJlZCA9IHByZWRpY3Qoc3ZtX2NsYXNzLCB3aWx0X3RyYWluKQpzdm0udHJhaW4ubWF0cml4ID0gY29uZnVzaW9uTWF0cml4KHN2bV90cmFpbmluZ19wcmVkLCB3aWx0X3RyYWluJGNsYXNzKQpzdm0udHJhaW4ubWF0cml4JG92ZXJhbGxbJ0FjY3VyYWN5J10Kc3ZtLnRyYWluLm1hdHJpeCRieUNsYXNzWydTcGVjaWZpY2l0eSddCmBgYAoKYGBge3Igc3ZtLXRlc3QsIGluY2x1ZGU9RkFMU0V9CnN2bV9wcmVkaWN0ID0gcHJlZGljdChzdm1fY2xhc3MsIHdpbHRfdGVzdCkKc3ZtLnRlc3QubWF0cml4ID0gY29uZnVzaW9uTWF0cml4KHN2bV9wcmVkaWN0LCB3aWx0X3Rlc3QkY2xhc3MpCnN2bS50ZXN0Lm1hdHJpeCRvdmVyYWxsWydBY2N1cmFjeSddCnN2bS50ZXN0Lm1hdHJpeCRieUNsYXNzWydTcGVjaWZpY2l0eSddCmBgYAoKKipMaW5lYXIga2VybmVsIFN1cHBvcnQgVmVjdG9yIE1hY2hpbmUqKgoKYGBge3Igc3ZtLWxpbmVhcn0Kc2V0LnNlZWQoMCkKdHVuZS5vdXQ9dHVuZShzdm0sIGNsYXNzfi4sIGRhdGE9d2lsdF90cmFpbiwga2VybmVsPSJsaW5lYXIiLAogICAgICAgICAgICAgIHJhbmdlcz1saXN0KGNvc3Q9YygwLjAwMSwwLjAxLDAuMSwxLDEwLDEwMCkpKSAKYmVzdG1vZCA9IHR1bmUub3V0JGJlc3QubW9kZWwKYGBgCmBgYHtyLCBlY2hvPUZBTFNFfQpiZXN0bW9kCmBgYAoKYGBge3Igc3ZtLWxpbmVhcnRyYWluLCBpbmNsdWRlPUZBTFNFfQpiZXN0bW9kX3RyYWluID0gcHJlZGljdChiZXN0bW9kLCB3aWx0X3RyYWluKQpzdm0ubGluZWFyLm1hdHJpeCA9IGNvbmZ1c2lvbk1hdHJpeChiZXN0bW9kX3RyYWluLCB3aWx0X3RyYWluJGNsYXNzKQpzdm0ubGluZWFyLm1hdHJpeCRvdmVyYWxsWydBY2N1cmFjeSddCnN2bS5saW5lYXIubWF0cml4JGJ5Q2xhc3NbJ1NwZWNpZmljaXR5J10KYGBgCgpgYGB7ciBzdm0tbGluZWFydGVzdCwgaW5jbHVkZT1GQUxTRX0KYmVzdG1vZF90ZXN0ID0gcHJlZGljdChiZXN0bW9kLCB3aWx0X3Rlc3QpCnN2bS5saW5lYXIudGVzdC5tYXRyaXggPSBjb25mdXNpb25NYXRyaXgoYmVzdG1vZF90ZXN0LCB3aWx0X3Rlc3QkY2xhc3MpCnN2bS5saW5lYXIudGVzdC5tYXRyaXgkb3ZlcmFsbFsnQWNjdXJhY3knXQpzdm0ubGluZWFyLnRlc3QubWF0cml4JGJ5Q2xhc3NbJ1NwZWNpZmljaXR5J10KYGBgCgoKKipSYWRpYWwga2VybmVsIFN1cHBvcnQgVmVjdG9yIE1hY2hpbmUqKgoKYGBge3Igc3ZtLXJhZGlhbH0Kc2V0LnNlZWQoMCkKcmFkdHVuZS5vdXQ9dHVuZShzdm0sIGNsYXNzfi4sIGRhdGE9d2lsdF90cmFpbiwga2VybmVsPSdyYWRpYWwnLAogICAgICAgICAgICAgICAgIHJhbmdlcz1saXN0KGNvc3Q9YygwLjAwMSwwLjAxLDAuMSwxLDEwLDEwMCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2FtbWE9YygwLjAxLDAuMSwxLDIsMyw0KSkpCmJlc3Rtb2RyYWQgPSByYWR0dW5lLm91dCRiZXN0Lm1vZGVsCmBgYAoKYGBge3IsIGVjaG89RkFMU0V9CmJlc3Rtb2RyYWQKYGBgCgpgYGB7ciBzdm0tcmFkaWFsdHJhaW4sIGluY2x1ZGU9RkFMU0V9CmJlc3Rtb2RyYWRfdHJhaW4gPSBwcmVkaWN0KGJlc3Rtb2RyYWQsIHdpbHRfdHJhaW4pCnN2bS5yYWRpYWwubWF0cml4ID0gY29uZnVzaW9uTWF0cml4KGJlc3Rtb2RyYWRfdHJhaW4sIHdpbHRfdHJhaW4kY2xhc3MpCnN2bS5yYWRpYWwubWF0cml4JG92ZXJhbGxbJ0FjY3VyYWN5J10Kc3ZtLnJhZGlhbC5tYXRyaXgkYnlDbGFzc1snU3BlY2lmaWNpdHknXQpgYGAKCmBgYHtyIHN2bS1yYWRpYWx0ZXN0LCBpbmNsdWRlPUZBTFNFfQpiZXN0bW9kcmFkX3Rlc3QgPSBwcmVkaWN0KGJlc3Rtb2RyYWQsIHdpbHRfdGVzdCkKc3ZtLnJhZGlhbC50ZXN0Lm1hdHJpeCA9IGNvbmZ1c2lvbk1hdHJpeChiZXN0bW9kcmFkX3Rlc3QsIHdpbHRfdGVzdCRjbGFzcykKc3ZtLnJhZGlhbC50ZXN0Lm1hdHJpeCRvdmVyYWxsWydBY2N1cmFjeSddCnN2bS5yYWRpYWwudGVzdC5tYXRyaXgkYnlDbGFzc1snU3BlY2lmaWNpdHknXQpgYGAKCgoqKioKIyMjIFJlc3VsdHMgYW5kIERpc2N1c3Npb246CgpUaGUgdGFibGUgYmVsb3cgc2hvd3MgdGhlIGNsYXNzaWZpY2F0aW9uIHJlc3VsdHMgZnJvbSB0aGUgcHJldmlvdXNseSBoaWdobGlnaHRlZCBtZXRob2RzLgpBY2N1cmFjeSByZWZlcnMgdG8gdGhlIGNsYXNzaWZpY2F0aW9uIGFjY3VyYWN5IG9mIGEgbWV0aG9kIHdoZW4gY2xhc3NpZnlpbmcgb2JzZXJ2YXRpb25zIGFjcm9zcwpib3RoIG9mIHRoZSBwcmVkaWN0aXZlIGNsYXNzZXMuClNwZWNpZmljaXR5IHJlZmVycyB0byB0aGUgY2xhc3NpZmljYXRpb24gYWNjdXJhY3kgb2YgYSBtZXRob2Qgd2hlbiBjbGFzc2lmeWluZyBvYnNlcnZhdGlvbnMgb2YKdGhlIGNsYXNzICd3aWx0JyBvbmx5LgoKYGBge3IgcmVzdWx0cywgaW5jbHVkZT1GQUxTRX0KbGFicyA9IGRhdGEuZnJhbWUoTWV0aG9kPWMoIkRlY2lzaW9uIFRyZWUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAiUHJ1bmVkIERlY2lzaW9uIFRyZWUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAiUmFuZG9tIEZvcmVzdCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJTdXBwb3J0IFZlY3RvciBNYWNoaW5lIChPT0IpIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIkxpbmVhciBTdXBwb3J0IFZlY3RvciBNYWNoaW5lIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIlJhZGlhbCBTdXBwb3J0IFZlY3RvciBNYWNoaW5lIikpCgp0cmFpbl9hY2N1cmFjeSA9IGRhdGEuZnJhbWUoVHJhaW4uQWNjdXJhY3k9YyhycC50cmFpbi5tYXRyaXgkb3ZlcmFsbFsnQWNjdXJhY3knXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJ1bmUudHJhaW4ubWF0cml4JG92ZXJhbGxbJ0FjY3VyYWN5J10sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvcmVzdC50cmFpbi5tYXRyaXgkb3ZlcmFsbFsnQWNjdXJhY3knXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3ZtLnRyYWluLm1hdHJpeCRvdmVyYWxsWydBY2N1cmFjeSddLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdm0ubGluZWFyLm1hdHJpeCRvdmVyYWxsWydBY2N1cmFjeSddLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdm0ucmFkaWFsLm1hdHJpeCRvdmVyYWxsWydBY2N1cmFjeSddKSkKCnRyYWluX3NwZWNpZmljaXR5ID0gZGF0YS5mcmFtZShUcmFpbi5TcGVjaWZpY2l0eT1jKHJwLnRyYWluLm1hdHJpeCRieUNsYXNzWydTcGVjaWZpY2l0eSddLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcnVuZS50cmFpbi5tYXRyaXgkYnlDbGFzc1snU3BlY2lmaWNpdHknXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9yZXN0LnRyYWluLm1hdHJpeCRieUNsYXNzWydTcGVjaWZpY2l0eSddLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdm0udHJhaW4ubWF0cml4JGJ5Q2xhc3NbJ1NwZWNpZmljaXR5J10sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN2bS5saW5lYXIubWF0cml4JGJ5Q2xhc3NbJ1NwZWNpZmljaXR5J10sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN2bS5yYWRpYWwubWF0cml4JGJ5Q2xhc3NbJ1NwZWNpZmljaXR5J10pKQoKYWNjdXJhY3kgPSBkYXRhLmZyYW1lKFRlc3QuQWNjdXJhY3k9YyhycC5tYXRyaXgkb3ZlcmFsbFsnQWNjdXJhY3knXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJ1bmUubWF0cml4JG92ZXJhbGxbJ0FjY3VyYWN5J10sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvcmVzdC5tYXRyaXgkb3ZlcmFsbFsnQWNjdXJhY3knXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3ZtLnRlc3QubWF0cml4JG92ZXJhbGxbJ0FjY3VyYWN5J10sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN2bS5saW5lYXIudGVzdC5tYXRyaXgkb3ZlcmFsbFsnQWNjdXJhY3knXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3ZtLnJhZGlhbC50ZXN0Lm1hdHJpeCRvdmVyYWxsWydBY2N1cmFjeSddKSkKCnNwZWNpZmljaXR5ID0gZGF0YS5mcmFtZShUZXN0LlNwZWNpZmljaXR5PWMocnAubWF0cml4JGJ5Q2xhc3NbJ1NwZWNpZmljaXR5J10sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBydW5lLm1hdHJpeCRieUNsYXNzWydTcGVjaWZpY2l0eSddLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb3Jlc3QubWF0cml4JGJ5Q2xhc3NbJ1NwZWNpZmljaXR5J10sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN2bS50ZXN0Lm1hdHJpeCRieUNsYXNzWydTcGVjaWZpY2l0eSddLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdm0ubGluZWFyLnRlc3QubWF0cml4JGJ5Q2xhc3NbJ1NwZWNpZmljaXR5J10sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN2bS5yYWRpYWwudGVzdC5tYXRyaXgkYnlDbGFzc1snU3BlY2lmaWNpdHknXSkpCgpyZXN1bHRzX3RhYmxlID0gY2JpbmQobGFicywgdHJhaW5fYWNjdXJhY3ksIHRyYWluX3NwZWNpZmljaXR5LCBhY2N1cmFjeSwgc3BlY2lmaWNpdHkpCmBgYAoKYGBge3IsIGVjaG89RkFMU0V9CnJlc3VsdHNfdGFibGUKYGBgCkZyb20gdGhlIHJlc3VsdHMgb2J0YWluZWQgdGhyb3VnaCB0aGUgYXNzZXNzZWQgbWV0aG9kcywgdGhlIHJhZGlhbCBzdXBwb3J0CnZlY3RvciBtYWNoaW5lIG1ldGhvZCBoYXMgcmVjb3JkZWQgdGhlIGVxdWFsIGhpZ2hlc3QgYWNjdXJhY3kgKDk5LjA3JSkgYW5kIHRoZSBoaWdoZXN0IApzcGVjaWZpY2l0eSAoOTUuOTIlKSBvbiB0aGUgdGVzdCBkYXRhc2V0LiBUaGUgcmFuZG9tIGZvcmVzdCBtZXRob2QgcmVjb3JkZWQgdGhlIHNlY29uZCBoaWdoZXN0IAphY2N1cmFjeSAoOTkuMDclKSBhbmQgc3BlY2lmaWNpdHkgKDkxLjg0JSkgb24gdGhlIHRlc3QgZGF0YXNldC4gRGVjaXNpb24gdHJlZSBtZXRob2RzIGFsc28gCnBlcmZvcm1lZCBjb21wYXJhdGl2ZWx5IHdlbGwgd2l0aCBhY2N1cmFjeSBhbmQgc3BlY2lmaWNpdHkgcmVzdWx0cyBvZiA5OC4zNSUgYW5kIDg1LjcxJSAKcmVzcGVjdGl2ZWx5IGZvciB0aGUgdW4tcHJ1bmVkIGRlY2lzaW9uIHRyZWUsIGFuZCA5OC4xNCUgYW5kIDgxLjYzJSByZXNwZWN0aXZlbHkgZm9yIHRoZSBwcnVuZWQgCmRlY2lzaW9uIHRyZWUuIFRoaXMgaXMgYW4gb2JzZXJ2YWJsZSByZWR1Y3Rpb24gaW4gCnNwZWNpZmljaXR5IGluIHRoZSBwcnVuZWQgZGVjaXNpb24gdHJlZSBpbiB0cmFkZSBmb3IgYSByZWxhdGl2ZWx5IG1pbm9yIHNpbXBsaWZpY2F0aW9uIGluIHRoZSAKcmVzdWx0aW5nIGRlY2lzaW9uIHRyZWUgbW9kZWwgKDE2IHRlcm1pbmFsIG5vZGVzIHZlcnN1cyAxMyB0ZXJtaW5hbCBub2RlcyB3aGVuIHBydW5lZCkuCkl0IGlzIGNsZWFyIGZyb20gYW5hbHlzaXMgb2YgdGhlIHJlc3VsdHMgdGhhdCBhbGwgbWV0aG9kcyByZWNvcmRlZCBzaW1pbGFyIGFjY3VyYWN5IHJlc3VsdHMKd2hlbiBlYWNoIG1vZGVsIHdhcyBhcHBsaWVkIG9uIHRoZSB0ZXN0IGRhdGFzZXQuIEFzIHN1Y2gsIGl0IGNhbiBiZSBzdGF0ZWQgdGhhdCBubyBtb2RlbCBpbgpwYXJ0aWN1bGFyIGNvdWxkIGJlIGRlc2NyaWJlZCB0byBoYXZlIGJlZW4gb3Zlci1maXR0ZWQgdG8gdGhlIHRyYWluaW5nIGRhdGFzZXQuCkl0IGlzIGFsc28gY2xlYXIgZnJvbSBhbmFseXNpcyB0aGF0IGFsbCBtZXRob2RzIHRlbmRlZCB0byBwZXJmb3JtIHdpdGggbGVzcyBwcmVjaXNpb24Kd2hlbiBzcGVjaWZpY2l0eSB3YXMgY29uc2lkZXJlZC4gQXNzZXNzaW5nIHRoZSBwcmVjaXNpb24gaW4gc3BlY2lmaWNpdHkgb2YgYSBtZXRob2QgaXMgCmltcG9ydGFudCB3aGVuIGNvbnNpZGVyYXRpb24gaXMgZ2l2ZW4gdG8gdGhlIHBvdGVudGlhbCBuZWdhdGl2ZSBjb25zZXF1ZW5jZXMgb2YgYSBmYWxzZS1uZWdhdGl2ZQp3aWx0IGRpc2Vhc2UgY2xhc3NpZmljYXRpb24uIE9uIHRoaXMgYmFzaXMsIHNwZWNpZmljaXR5IGFzIGEgZGV0ZXJtaW5pbmcgZmFjdG9yIGluIHRoZSBvdmVyYWxsCmFzc2Vzc21lbnQgb2YgdGhlIGNsYXNzaWZpY2F0aW9uIGFjY3VyYWN5IHNpbXBseSBjYW5ub3QgYmUgaWdub3JlZC4KCioqKgojIyMgQ29uY2x1c2lvbnM6CgpJbiBjb25jbHVzaW9uLCB0aGlzIHByb2plY3QgaGFzIGFzc2Vzc2VkIGFuZCBjb21wYXJlZCBkZWNpc2lvbiB0cmVlcywgcmFuZG9tIGZvcmVzdAplbnNlbWJsZXMgZm9yIGRlY2lzaW9uIHRyZWVzIGFuZCBzdXBwb3J0IHZlY3RvciBtYWNoaW5lcyBpbiB0aGUgY29udGV4dCBvZiBpZGVudGlmeWluZyAKZGlzZWFzZWQgdHJlZXMgaW4gdGhlIHdpbHQgZGF0YXNldC4gQSByYWRpYWwga2VybmVsIHN1cHBvcnQgdmVjdG9yIG1hY2hpbmUgd2FzIGlkZW50aWZpZWQKYXMgYSBoaWdobHkgYWNjdXJhdGUgYW5kIHNwZWNpZmljIGNsYXNzaWZ5aW5nIG1ldGhvZCBmb3IgdGhlIGRldGVjdGlvbiBvZiB3aWx0IGRpc2Vhc2VkCnRyZWVzLgoKKioqCiMjIyBSZWZlcmVuY2VzOgoKQnJlaW1hbiwgTC4gKDIwMDEpLiAiUmFuZG9tIEZvcmVzdHMiLCBodHRwczovL3d3dy5zdGF0LmJlcmtlbGV5LmVkdS9+YnJlaW1hbi9yYW5kb21mb3Jlc3QyMDAxLnBkZgoKRm9vZCBhbmQgQWdyaWN1bHR1cmUgT3JnYW5pemF0aW9uIG9mIHRoZSBVbml0ZWQgTmF0aW9ucyBSZWdpb25hbCBPZmZpY2UgZm9yIEFzaWEgYW5kIHRoZSBQYWNpZmljLgooMjAxMCkuIOKAnEphcGFuIEZvcmVzdHJ5IE91dGxvb2sgU3R1ZHku4oCdIEluIEFzaWEtUGFjaWZpYyBGb3Jlc3RyeSBTZWN0b3IgT3V0bG9vayBTdHVkeSBJSSBXb3JraW5nClBhcGVyIFNlcmllcywgOeKAkzEwLiBXb3JraW5nIFBhcGVyIE5vLiBBUEZTT1MgSUkvV1AvMjAxMC8zMC4KCkpvaG5zb24sIEIuLCBUYXRlaXNoaSwgUi4sIEhvYW4sIE4uICgyMDEzKS4gIkEgaHlicmlkIHBhbnNoYXJwZW5pbmcgYXBwcm9hY2ggYW5kIG11bHRpc2NhbGUgb2JqZWN0LWJhc2VkIGltYWdlIGFuYWx5c2lzIGZvciBtYXBwaW5nIGRpc2Vhc2VkIHBpbmUgYW5kIG9hayB0cmVlcyIsIEludGVybmF0aW9uYWwgSm91cm5hbCBvZiBSZW1vdGUgU2Vuc2luZywgMzQgKDIwKSwgNjk2OS02OTgyLiAKCkdhcnJldHQsIEsuLCBEZW5keSwgUy4sIEZyYW5rLCBFLiwgUm91c2UsIE0uLCBUcmF2ZXJzLCBNLiwgKDIwMDYpIOKAnENsaW1hdGUgY2hhbmdlIGVmZmVjdHMgb24gcGxhbnQgZGlzZWFzZTogZ2Vub21lcyB0byBlY29zeXN0ZW1zLOKAnSBBbm51YWwgUmV2aWV3IG9mIFBoeXRvcGF0aG9sb2d5LCBWb2wuIDQ0LCBwcC4gNDg54oCTNTA5LCAyMDA2LgoKKioqCiMjIyBBcHBlbmRpY2VzOgoKRGF0YXNldCBzb3VyY2U6IGh0dHA6Ly9hcmNoaXZlLmljcy51Y2kuZWR1L21sL2RhdGFzZXRzL3dpbHQK